package com.gao.window;

import com.gao.netclient.NetClient;
import com.gao.netclient.Request;
import com.gao.netclient.Response;
import com.gao.template.TemplateProvider;
import com.gao.util.MessageUtil;
import com.gao.util.XmlFormat;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import org.fife.ui.rsyntaxtextarea.*;
import org.fife.ui.rtextarea.RTextScrollPane;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.List;

public class NetBankWindow {
    private JPanel mainWindow;
    private JTextField ip;
    private JComboBox charset;
    private JTextField port;
    private JTextField header;
    private JTextField timeout;
    private JComboBox tranFun;
    private JButton send;
    private JButton format;
    private JButton compress;
    private JTextField stat;
    private JProgressBar progressBar1;
    private JButton copy;
    private JPanel requestPanel;
    private JPanel responsePanel;
    private JButton saveAsTemplate;
    private JButton clearResponse;
    private JButton deleteTemplate;
    private JLabel msgLabel;

    private RSyntaxTextArea xmlText1;
    private RSyntaxTextArea xmlText2;
    // 主题模式
    private boolean isDarcula = false;
    // 格式化标志
    private boolean isFormated = false;

    private static final String XML = "XML";
    private static final String REQUEST_PROPERTIES = "/request.properties";


    TemplateProvider templateProvider;
    // 模板缓存
    Map<String, Object> templateMap;
    MessageUtil messageUtil;

    public JPanel getMainWindow() {
        return mainWindow;
    }

    public NetBankWindow() {
    }

    public NetBankWindow(Project project, ToolWindow toolWindow, boolean isDarcula) {
        this.isDarcula = isDarcula;
        init();

        /** 发送事件监听 */
        send.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 单独线程执行请求任务，避免 UI 卡死
                new Thread(() -> {
                    send();
                }).start();
            }
        });

        /** 接口代码数据变更事件监听 */
        tranFun.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                //Object item = e.getItem();
                JComboBox comboBox = (JComboBox) e.getSource();
                Object item = comboBox.getSelectedItem();
                xmlText1.setText(templateProvider.getFileContent(item.toString()));
            }
        });

        /** 模板保存事件监听 */
        saveAsTemplate.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String tempCode = tranFun.getSelectedItem().toString();
                templateProvider.saveAsTemplate(tempCode, xmlText1.getText());
                refreshTemplate(tranFun, templateMap);
                // 选中最后一次选择的模板
                tranFun.setSelectedItem(tempCode);
            }
        });

        /** 模板删除事件监听 */
        deleteTemplate.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String tempCode = tranFun.getSelectedItem().toString();
                templateProvider.deleteTemplate(tempCode);
                //refreshTemplate(tranFun, templateMap);
                templateProvider.refreshTemplateFile(templateMap);
                templateMap.remove(tempCode);
                tranFun.removeItem(tempCode);
            }
        });

        /** 格式化按钮事件监听 */
        format.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (!isFormated) {
                    xmlOK(xmlText2.getText());
                } else {
                    xmlCompress(xmlText2.getText());
                }

            }
        });

        /** 压缩按钮事件监听 */
        compress.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                xmlCompress(xmlText2.getText());
            }
        });

        /** 清除按钮事件监听 */
        clearResponse.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                xmlText2.setText("");
                stat.setText("返回内容已清空！");
            }
        });

        /** 复制按钮事件监听 */
        copy.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                Transferable transferable = new StringSelection(xmlText2.getText());
                clipboard.setContents(transferable, null);
                stat.setText("复制到剪切板！");
            }
        });
    }


    /**
     * 初始化
     */
    public void init() {
        templateProvider = new TemplateProvider();
        templateProvider.templateProd();
        templateMap = templateProvider.getTemplateMap();
        messageUtil = new MessageUtil();
        createRSyntaxTextArea();
        setDefaultValue();
    }

    /**
     * 初始化时，设置默认值
     */
    public void setDefaultValue() {
        xmlText1.setLineWrap(true);
        xmlText2.setLineWrap(true);

        // 从模板中获取请求内容
        Properties properties = getFromProperties();
        String strIp = properties.getProperty("IP");
        String strPort = properties.getProperty("Port");
        String strCharset = properties.getProperty("Charset");
        String headerlen = properties.getProperty("HeaderLen");
        String strTimeout = properties.getProperty("TimeOut");

        ip.setText(strIp == null ? "127.0.0.1" : strIp);
        port.setText(strPort == null ? "8102" : strPort);
        header.setText(headerlen == null ? "8" : headerlen);
        timeout.setText(strTimeout == null ? "20" : strTimeout);
        // charset
        charset.addItem("GBK");
        charset.addItem("UTF-8");
        charset.addItem("GB2312");
        charset.setSelectedItem(strCharset == null ? "GBK" : strCharset);

        //List<String> tranFunList = templateProvider.getTranFunList();
        // 遍历目录获取模板名称
        addTemplate(templateMap);
        stat.setText("插件地址："+templateProvider.getPluginPath());
    }

    /**
     * 添加模板代码
     * @param map
     */
    public void addTemplate(Map<String, Object> map) {
        Iterator iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String next = (String) iterator.next();
            tranFun.removeItem(next);
            tranFun.addItem(next);
        }
    }


    public List<String> getAllItem(JComboBox tranFun) {
        List<String> list = new ArrayList<>();
        ComboBoxModel model = tranFun.getModel();
        for (int i = 0; i < model.getSize(); i++) {
            list.add((String) model.getElementAt(i));
        }
        return list;
    }


    public void send() {
        Request requestInfo = new Request();
        stat.setText("");
        String requestText = xmlText1.getText();

        String strIp = ip.getText();
        String strPort = port.getText();
        String strCharset = (String) charset.getSelectedItem();
        String headerlen = header.getText();
        String strTimeout = timeout.getText();

        if (strIp == null || strIp.isEmpty()) {
            strIp = "127.0.0.1";
        }
        if (strPort == null || strPort.isEmpty()) {
            strPort = "8102";
        }
        if (strCharset == null || strCharset.isEmpty()) {
            strCharset = "GBK";
        }
        if (headerlen == null || headerlen.isEmpty()) {
            headerlen = "8";
        }
        if (strTimeout == null || strTimeout.isEmpty()) {
            strTimeout = "20";
        }

        if (requestText.isEmpty()) {
            stat.setText("请求报文不可为空！");
            messageUtil.alertMsg("请求报文不可为空！");
            return;
        }

        requestInfo.setIp(strIp);
        requestInfo.setPort(Integer.valueOf(strPort));
        requestInfo.setCharset(strCharset);
        requestInfo.setHeaderLen(Integer.valueOf(headerlen));
        requestInfo.setTimeout(Integer.valueOf(strTimeout));
        requestInfo.setData(requestText);

        // 将请求信息保存到模板
        saveAsProperties(requestInfo);

        NetClient netClient= new NetClient();
        System.out.println(requestInfo.toString());
        Response responseInfo = netClient.sendRequest(requestInfo);
        xmlText2.setText(responseInfo.getResData());
        stat.setText(responseInfo.getMsg());
        //xmlOK(responseInfo.getResData());
    }

    private void createRSyntaxTextArea() {
        xmlText1 = createArea(XML);
        xmlText2 = createArea(XML);
        RTextScrollPane xmlSp1 = new RTextScrollPane(xmlText1);
        RTextScrollPane xmlSp2 = new RTextScrollPane(xmlText2);
        xmlSp1.setBorder(new EmptyBorder(new Insets(10, 0, 0, 0)));
        xmlSp2.setBorder(new EmptyBorder(new Insets(10, 0, 0, 0)));
        requestPanel.add(xmlSp1);
        responsePanel.add(xmlSp2);
    }

    private RSyntaxTextArea createArea(String type) {
        RSyntaxTextArea area = new RSyntaxTextArea();
        area.setDocument(new MaxLengthDocument(5000000));
        area.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_XML);
        area.setCodeFoldingEnabled(true);
        area.setAntiAliasingEnabled(true);
        area.setAutoscrolls(true);
        if (true == isDarcula) {
            try {
                Theme theme = Theme.load(getClass().getResourceAsStream("/org/fife/ui/rsyntaxtextarea/themes/dark.xml"));
                theme.apply(area);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            SyntaxScheme scheme = area.getSyntaxScheme();
            scheme.getStyle(Token.LITERAL_STRING_DOUBLE_QUOTE).foreground = Color.BLUE;
            scheme.getStyle(Token.LITERAL_NUMBER_DECIMAL_INT).foreground = new Color(164, 0, 0);
            scheme.getStyle(Token.LITERAL_NUMBER_FLOAT).foreground = new Color(164, 0, 0);
            scheme.getStyle(Token.LITERAL_BOOLEAN).foreground = Color.RED;
            scheme.getStyle(Token.OPERATOR).foreground = Color.BLACK;
            area.revalidate();
        }
        return area;
    }

    public class MaxLengthDocument extends RSyntaxDocument {
        int maxChars;

        public MaxLengthDocument(int max) {
            super(SYNTAX_STYLE_NONE);
            maxChars = max;
        }

        @Override
        public void insertString(int offset, String s, AttributeSet a) throws BadLocationException {
            try {
                if (getLength() + s.length() > maxChars) {
                    Toolkit.getDefaultToolkit().beep();
                    messageUtil.alertMsg("内容过长，最大" + maxChars + "个字符!");
                    return;
                }
                super.insertString(offset, s, a);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }

    public Properties getFromProperties() {
        Properties properties = new Properties();
        FileInputStream in = null;
        try {
            in = new FileInputStream(templateProvider.getPluginPath() + REQUEST_PROPERTIES);
            properties.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return properties;
    }

    public void saveAsProperties(Request res) {
        Properties properties = new Properties();
        properties.setProperty("IP", res.getIp());
        properties.setProperty("Port", String.valueOf(res.getPort()));
        properties.setProperty("Charset", res.getCharset());
        properties.setProperty("HeaderLen", String.valueOf(res.getHeaderLen()));
        properties.setProperty("TimeOut", String.valueOf(res.getTimeout()));
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(templateProvider.getPluginPath() + REQUEST_PROPERTIES);
            properties.store(out, "socket request info");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    // xml 格式化
    private void xmlOK(String text) {
        if (null == text || "".equalsIgnoreCase(text)) {
            stat.setText("格式化字符串不可为空！");
            return;
        }
        String header = text.substring(0, text.indexOf("<"));
        text = text.substring(text.indexOf("<"), text.length());
        text = text.replaceAll("\t", "");
        try {
            String resStr = header + XmlFormat.xmlFormat(text);
            stat.setText("xml 格式化成功!");
            xmlText2.setText(resStr);
            isFormated = true;
        } catch (Throwable e) {
            String eStr = "xml 格式化失败 [" + e.getMessage() + "]";
            stat.setText(eStr);
            stat.setToolTipText(eStr);
        }
    }

    /**
     * xml 压缩
     * @param text
     */
    private void xmlCompress(String text) {
        if (null == text || "".equalsIgnoreCase(text)) {
            stat.setText("格式化字符串不可为空！");
            return;
        }
        String header = text.substring(0, text.indexOf("<"));
        text = text.substring(text.indexOf("<"), text.length());
        try {
            String resStr = header + XmlFormat.compress(text);
            xmlText2.setText(resStr);
            stat.setText("压缩成功!");
            isFormated = false;
        } catch (Exception e) {
            e.printStackTrace();
            String eStr = "压缩失败 [" + e.getMessage() + "]";
            stat.setText(eStr);
            stat.setToolTipText(eStr);
        }
    }

    /**
     * 刷新模板
     * @param template
     * @param map
     */
    public void refreshTemplate(JComboBox template, Map map) {
        map.clear();
        // 重新刷新模板列表
        templateProvider.refreshTemplateFile(map);
        addTemplate(map);
    }

}
